package com.queue;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author yijy
 * @description
 * @create 2021/4/1 下午2:18
 **/
public class MessageQueue<E> {

    private String[] table;
    private ReentrantLock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
    int current;
    int putIndex ;
    int takeIndex ;

    public MessageQueue(int length) {
        this.table = new String[length];
    }

    /**
     * 1。加锁，防止线程资源竞争
     * 2。比较当前数量是否大于等于当前队列容量
     *    2.1 如果是，提醒非空队列，并且让不满队列暂停,开始轮训第二部操作
     *    2.2 如果不是，继续执行下一步
     * 3. 将新的值放入到数组对应序列
     * @param a
     */
    public void offer(String a) {
        lock.lock();
        try{
            while (current >= table.length) {
                notEmpty.signal();
                System.out.println("仓库已满"+Thread.currentThread().getName());
                notFull.await();
            }
            table[putIndex] = a;
            if(++putIndex == table.length){
                putIndex = 0;
            }
            current ++;
            System.out.println("线程"+Thread.currentThread().getName()+",生成一个线程"+a);
            notEmpty.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public String take() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        String r;
        try{
            while (current == 0) {
                notEmpty.await();
            }
            r = table[takeIndex];
            System.out.println(Thread.currentThread().getName()+"，获取" + r);
            table[takeIndex] = null;
            if(++takeIndex == table.length){
                takeIndex = 0;
            }
            current--;
            notFull.signal();
            return r;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }

}
